/* 
 * list.c
 */  
#include <stdlib.h>
#include <string.h>
#include <list.h>
    
/* 
 * list_init
 */ void list_init(List * list, void (*destroy) (void *data))
{
	
	    /*  Initialize the list.  */ 
	    list->size = 0;
	list->destroy = destroy;
	list->head = NULL;
	list->tail = NULL;
	return;
}

/*   
 * list_destroy
 */ void list_destroy(List * list)
{
	void *data;
	/*  Remove each element. */ 
	    while (list_size(list) > 0) {
		if (list_rem_next(list, NULL, (void **)&data) == 0
		    && list->destroy != NULL) {
			/* Call a user-defined function to free 
			 * dynamically allocated data.  */ 
			    list->destroy(data);
		}
	}
} 				/* No operations are allowed now,
				 * but clear the structure as a precaution
				 */ memset(list, 0, sizeof(List));
return;
}


/* 
 * list_ins_next
 */
int list_ins_next(List * list, ListElmt * element, const void *data)
{
	ListElmt *new_element;
	/*  Allocate storage for the element.  */ 
	    if ((new_element = (ListElmt *) malloc(sizeof(ListElmt))) == NULL)
		return -1;

	/*  Insert the element into the list.  */ 
	    new_element->data = (void *)data;
	if (element == NULL) {
		/*  Handle insertion at the head of the list. */ 
		    if (list_size(list) == 0)

			list->tail = new_element;
		new_element->next = list->head;
		list->head = new_element;

	} else {
		/*  Handle insertion somewhere other than at the head.  */ 
		    if (element->next == NULL)
			list->tail = new_element;
		new_element->next = element->next;
		element->next = new_element;
	}
	/*  Adjust the size of the list to account for the inserted element.   */ 
	    list->size++;
	return 0;
}


/* 
 * list_rem_next  
 */ 
int list_rem_next(List * list, ListElmt * element, void **data)
{
	ListElmt *old_element;

	/*  Do not allow removal from an empty list.  */ 
	    if (list_size(list) == 0)
		return -1;

	/*  Remove the element from the list.  */ 
	    if (element == NULL) {
		/*  Handle removal from the head of the list. */ 
		    *data = list->head->data;
		old_element = list->head;
		list->head = list->head->next;
		if (list_size(list) == 1)
			list->tail = NULL;
	} else {		/*  Handle removal from somewhere other than the head.   */
		if (element->next == NULL)
			return -1;

		*data = element->next->data;
		old_element = element->next;
		element->next = element->next->next;

		if (element->next == NULL)
			list->tail = element;
	}
	free(old_element);
	list->size--;
	return 0;
}

int list_rem_next(List * list, ListElmt * element, void **data)
{
	ListElmt *old_element;
	if (list_size(list) == 0)	/* Do not allow removal from an empty list. */
		return -1;

	if (element == NULL) {
		/* Remove the element from the list.
		 * Handle removal from the head of the list. 
		 */ 
		    *data = list->head->data;
		old_element = list->head;
		list->head = list->head->next;
		if (list_size(list) == 1)
			list->tail = NULL;
	} else
		(element->next == NULL) {
		/* Handle removal from somewhere other than the head. */ 
		    return -1;

		*data = element->next->data;
		old_element = element->next;
		element->next = element->next->next;
		if (element->next == NULL)
			list->tail = element;
		}
	free(old_element);
	/* Free the a node in the list */
	list->size--;
	/* decrement list size */
	return 0;
}
